package com.gitee.beiding.template_excel;

import com.alibaba.fastjson.JSONObject;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//提取器
public class Extractor {


    static {
        ZipSecureFile.setMinInflateRatio(-1d);
    }


    //--------------------------------Sheet页提取--------------------------------

    /**
     * 按照给定的提取模式进行提取
     *
     * @param template 模板sheet页
     * @param data     数据sheet页
     * @return 提取的结果
     */
    public static ExtractResult extract(XSSFSheet template, XSSFSheet data, ExtractContext extractContext) {

        /*
            创建一个两侧运动的指针
         */
        DoubleActingIndex doubleActingIndex = new DoubleActingIndex();

        //创建一个所有列的值的持有者
        Map<String, List<ValueHolder>> colValueMap = new HashMap<>();

        //创建一个模板sheet的持有
        TemplateSheetHolder templateSheetHolder = new TemplateSheetHolder(template, colValueMap, extractContext.getCellMatchingMode());

        //创建一个数据sheet的持有
        DataSheetHolder dataSheetHolder = new DataSheetHolder(data, templateSheetHolder);

        //设置运动指针的左侧对象
        doubleActingIndex.setLeft(templateSheetHolder);

        //设置运动指针的右侧对象
        doubleActingIndex.setRight(dataSheetHolder);

        //运动并提取数据
        while (doubleActingIndex.next()) {

        }

        //设置值持有者
        ValueHandler valueHandler = new ValueHandler();

        //设置实体类型映射
//        valueHandler.setEntityMapping(entityMapping);

        //处理列值
        return new ExtractResult(valueHandler.handle(colValueMap));
    }


    /**
     * 使用模板Map对data进行提取
     *
     * @param template 模板
     * @param data 数据
     * @param templateToDataMap 指定用模板sheet提取数据sheet的映射关系,如果不指定则同名提取
     * @return 提取结果
     */
    public static ExtractResult extract(XSSFWorkbook template, XSSFWorkbook data, Map<String, String> templateToDataMap, ExtractContext extractContext) {

        if (templateToDataMap == null) {
            templateToDataMap = new HashMap<>();
            //同名抽取
            for (int i = 0; i < template.getNumberOfSheets(); i++) {
                String sheetName = template.getSheetAt(i).getSheetName();
                XSSFSheet sheet = data.getSheet(sheetName);
                if (sheet != null) {
                    templateToDataMap.put(sheetName, sheetName);
                }
            }
        }

        JSONObject map = new JSONObject();

        templateToDataMap.forEach((k, v) -> {
            XSSFSheet t = template.getSheet(k);
            XSSFSheet d = data.getSheet(v);
            map.putAll(extract(t, d, extractContext).getData());
        });
        return new ExtractResult(map);
    }


    private static Map<Integer, Map<Integer, Merge>> handleMerge(List<CellRangeAddress> cellRangeAddresses) {
        Map<Integer, Map<Integer, Merge>> map = new HashMap<>();
        if (cellRangeAddresses.size() > 0) {
            for (CellRangeAddress cellRangeAddress : cellRangeAddresses) {
                Map<Integer, Merge> absent = map.computeIfAbsent(cellRangeAddress.getFirstRow(), k -> new HashMap<>());
                absent.computeIfAbsent(cellRangeAddress.getFirstColumn(), k -> Merge.get(cellRangeAddress.getLastRow() - cellRangeAddress.getFirstRow() + 1, cellRangeAddress.getLastColumn() - cellRangeAddress.getFirstColumn() + 1));
            }
        }
        return map;
    }

    private static class TemplateSheetHolder implements DoubleActingIndex.Handle {

        XSSFSheet template;

        //当前指针
        int current;

        //指针最大
        int max;

        Map<Integer, Map<Integer, Merge>> margeMap;

        Map<String, List<ValueHolder>> colValueMap;

        private ColNumberMatchingMode colModel;

        TemplateSheetHolder(XSSFSheet template, Map<String, List<ValueHolder>> colValueMap, ColNumberMatchingMode colModel) {
            this.colModel = colModel;
            this.colValueMap = colValueMap;
            this.template = template;
            this.current = template.getFirstRowNum();
            this.max = template.getLastRowNum();
            this.margeMap = handleMerge(template.getMergedRegions());

            //初始化的时候跳转一次
            next();
        }

        /**
         * 模板行
         */
        TemplateRow templateRow;

        Map<Integer, Merge> empty = Collections.emptyMap();

        Map<Integer, Merge> getMerge(int row) {
            Map<Integer, Merge> mergeMap = margeMap.get(row);
            if (mergeMap == null) {
                mergeMap = empty;
            }
            return mergeMap;
        }

        @Override
        public boolean next() {
            while (true) {

                if (current > max) {
                    return false;
                }
                templateRow = TemplateRow.compile(template.getRow(current), getMerge(current), colValueMap, colModel);

                current++;
                if (templateRow != null) {//空白行不能作为模板行,没有任何意义
                    return true;
                }

            }
        }

        @Override
        public boolean shouldChange() {//总是跳转到另一行中
            return true;
        }

        @Override
        public void afterChange() {

        }

        @Override
        public void afterChangeTo() {

        }

        TemplateRow getTemplateRow() {
            return templateRow;
        }
    }


    private static class DataSheetHolder implements DoubleActingIndex.Handle {

        XSSFSheet data;

        //当前指针
        int current;

        //指针最大
        int max;

        Map<Integer, Map<Integer, Merge>> margeMap;

        XSSFRow row;

        Map<Integer, Merge> empty = Collections.emptyMap();

        Map<Integer, Merge> getMerge(int row) {
            Map<Integer, Merge> mergeMap = margeMap.get(row);
            if (mergeMap == null) {
                mergeMap = empty;
            }
            return mergeMap;
        }

        //可用于获取模板行数据
        TemplateSheetHolder templateSheetHolder;

        DataSheetHolder(XSSFSheet data, TemplateSheetHolder templateSheetHolder) {
            this.templateSheetHolder = templateSheetHolder;
            this.data = data;
            this.current = data.getFirstRowNum();
            this.max = data.getLastRowNum();
            margeMap = handleMerge(data.getMergedRegions());
        }

        @Override
        public boolean next() {
            while (true) {
                if (current > max) {
                    return false;
                }
                row = data.getRow(current);
                merge = getMerge(current);
                current++;
                if (row != null) {
                    return true;
                }
            }
        }

        Map<Integer, Merge> merge;

        @Override
        public boolean shouldChange() {

            //TODO 处理跳转逻辑
            TemplateRow templateRow = templateSheetHolder.getTemplateRow();


            boolean b = templateRow.extract(row, merge);

            //表明当前行已经不符合模板行
            if (!b) {

                //指针后移一下,在变更模板行后重新判断当前行中的数据是否符合模板行
                current--;

                //改变模板行
                return true;

            }

            return false;
        }

        @Override
        public void afterChange() {
        }

        @Override
        public void afterChangeTo() {

        }
    }

}
